package com.example.multi.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.concurrent.*;

/**
 * 线程池配置（@Async）
 */
@Slf4j
@EnableAsync
@Configuration
public class SimpleExecutorConfig implements AsyncConfigurer {
    /** 线程池维护线程的最少数量 */
    @Value("${executor.corePoolSize}")
    private Integer corePoolSize;

    /** 线程池维护线程的最大数量 */
    @Value("${executor.maxPoolSize}")
    private Integer maxPoolSize;

    /** 缓冲队列的大小 */
    @Value("${executor.queueCapacity}")
    private Integer queueCapacity;

    /** 为每个线程名设置一个前缀（1） */
    @Value("${executor.threadNamePrefix}")
    private String threadNamePrefix;

    /** 为每个线程名设置一个前缀（2） */
    @Value("${executor.threadNamePrefix_2}")
    private String threadNamePrefix_2;

    @Value("${executor.threadNamePrefix_3}")
    private String threadNamePrefix_3;

    @Value("${executor.threadNamePrefix_4}")
    private String threadNamePrefix_4;


    @Bean(ExecutorConstant.simpleExecutor_1)
    @Override
    public Executor getAsyncExecutor() {
        //线程池
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(corePoolSize);
        taskExecutor.setMaxPoolSize(maxPoolSize);
        taskExecutor.setQueueCapacity(queueCapacity);
        taskExecutor.setThreadNamePrefix(threadNamePrefix);
        taskExecutor.initialize();
        return taskExecutor;
    }


    @Bean(ExecutorConstant.simpleExecutor_2)
    public Executor asyncExecutor2() {
        //线程池
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(corePoolSize);
        taskExecutor.setMaxPoolSize(maxPoolSize);
        taskExecutor.setQueueCapacity(queueCapacity);
        taskExecutor.setThreadNamePrefix(threadNamePrefix_2);
        taskExecutor.initialize();
        return taskExecutor;
    }


    @Bean(ExecutorConstant.simpleExecutor_3)
    public Executor asyncExecutor3() {
        MyThreadPoolTaskExecutor taskExecutor = new MyThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(corePoolSize);
        taskExecutor.setMaxPoolSize(maxPoolSize);
        taskExecutor.setQueueCapacity(queueCapacity);
        taskExecutor.setThreadNamePrefix(threadNamePrefix_3);
        taskExecutor.initialize();
        return taskExecutor;
    }

    //------- 实现TaskDecorator 接口 start

    @Bean(ExecutorConstant.simpleExecutor_4)
    public Executor asyncExecutor4() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(corePoolSize);
        taskExecutor.setMaxPoolSize(maxPoolSize);
        taskExecutor.setQueueCapacity(queueCapacity);
        taskExecutor.setThreadNamePrefix(threadNamePrefix_4);
        taskExecutor.setTaskDecorator(new MyTaskDecorator());
        taskExecutor.initialize();
        return taskExecutor;
    }
    //------- 实现TaskDecorator 接口 end

    //------- 继承ThreadPoolExecutor类重写execute方法 start
    @Bean(ExecutorConstant.simpleExecutor_5)
    public Executor asyncExecutor5() {

        MyThreadPoolExecutor executorService = new MyThreadPoolExecutor(50, 200,
                180L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<Runnable>(3000), new ThreadFactory() {

            final ThreadFactory defaultFactory = Executors.defaultThreadFactory();

            @Override
            public Thread newThread(Runnable r) {
                Thread thread = defaultFactory.newThread(r);
                thread.setName("threadNamePrefix_5 - " + thread.getName());
                return thread;
            }
        }, new ThreadPoolExecutor.CallerRunsPolicy());

        return executorService;
    }
    //------- 继承ThreadPoolExecutor类重写execute方法 end

    class MyTaskDecorator implements TaskDecorator{

        @Override
        public Runnable decorate(Runnable runnable) {
            try {
                RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
                return () -> {
                    try {
                        RequestContextHolder.setRequestAttributes(attributes);
                        runnable.run();
                    } finally {
                        RequestContextHolder.resetRequestAttributes();
                    }
                };
            } catch (IllegalStateException e) {
                return runnable;
            }
        }
    }
    //------- 实现TaskDecorator 接口 end

    //------- ThreadPoolTaskExecutor 继承父类 重写对应的方法 start
    class MyCallable<T> implements Callable<T> {
        private Callable<T> task;
        private RequestAttributes context;

        public MyCallable(Callable<T> task, RequestAttributes context) {
            this.task = task;
            this.context = context;
        }

        @Override
        public T call() throws Exception {
            if (context != null) {
                RequestContextHolder.setRequestAttributes(context);
            }

            try {
                return task.call();
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        }
    }

    class MyThreadPoolTaskExecutor extends ThreadPoolTaskExecutor{

        @Override
        public <T> Future<T> submit(Callable<T> task) {
            return super.submit(new MyCallable(task, RequestContextHolder.currentRequestAttributes()));
        }

        @Override
        public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
            return super.submitListenable(new MyCallable(task, RequestContextHolder.currentRequestAttributes()));
        }
    }
    //------- ThreadPoolTaskExecutor 继承父类 重写对应的方法 start

    //------- ThreadPoolExecutor 继承父类 重写对应的方法 start
    class MyRunnable implements Runnable {
        private Runnable runnable;
        private RequestAttributes context;

        public MyRunnable(Runnable runnable, RequestAttributes context) {
            this.runnable = runnable;
            this.context = context;
        }

        @Override
        public void run() {
            if (context != null) {
                RequestContextHolder.setRequestAttributes(context);
            }
            try {
                runnable.run();
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        }
    }

    class MyThreadPoolExecutor extends ThreadPoolExecutor{
        @Override
        public void execute(Runnable command) {
            if(!(command instanceof MyRunnable)){
                command = new MyRunnable(command,RequestContextHolder.currentRequestAttributes());
            }
            super.execute(command);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        }
    }
    //------- ThreadPoolExecutor 继承父类 重写对应的方法 end
}
